#######################################################################
#
# Author: Malte Helmert (helmert@informatik.uni-freiburg.de)
# (C) Copyright 2003-2004 Malte Helmert
# Modified by: Gabi Roeger and Silvia Richter (silvia.richter@nicta.com.au)
# (C) Copyright 2008: Gabi Roeger and NICTA
#
# This file is part of LAMA.
#
# LAMA is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the license, or (at your option) any later version.
#
# LAMA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
#######################################################################

# Renamed from types.py to avoid clash with stdlib module.
# In the future, use explicitly relative imports or absolute
# imports as a better solution.

import conditions

import graph

import itertools

class Type(object):
  def __init__(self, name, basetype_name=None):
    self.name = name
    self.basetype_name = basetype_name
  def __str__(self):
    return self.name
  def __repr__(self):
    return "Type(%s, %s)" % (self.name, self.basetype_name)

def set_supertypes(type_list):
  typename_to_type = {}
  child_types = []
  for type in type_list:
    type.supertype_names = []
    typename_to_type[type.name] = type
    if type.basetype_name:
      child_types.append((type.name, type.basetype_name))
  for (desc_name, anc_name) in graph.transitive_closure(child_types):
    typename_to_type[desc_name].supertype_names.append(anc_name)


class TypedObject(object):
  def __init__(self, name, type):
    self.name = name
    self.type = type
  def __hash__(self):
    return hash((self.name, self.type))
  def __eq__(self, other):
    return self.name == other.name and self.type == other.type
  def __ne__(self, other):
    return not self == other
  def __str__(self):
    return "%s: %s" % (self.name, self.type)
  def uniquify_name(self, type_map, renamings):
    if self.name not in type_map:
      type_map[self.name] = self.type
      return self
    for counter in itertools.count(1):
      new_name = self.name + str(counter)
      if new_name not in type_map:
        renamings[self.name] = new_name
        type_map[new_name] = self.type
        return TypedObject(new_name, self.type)
  def to_untyped_strips(self):
    return conditions.Atom(self.type, [self.name])

def parse_typed_list(alist, only_variables=False, constructor=TypedObject, functions=False):
  result = []
  while alist:
    try:
      separator_position = alist.index("-")
    except ValueError:
      items = alist
      if functions:
        _type = "number"
      else:
        _type = "object"
      alist = []
    else:
      items = alist[:separator_position]
      _type = alist[separator_position + 1]
      alist = alist[separator_position + 2:]
    for item in items:
      assert not only_variables or item.startswith("?")
      entry = constructor(item, _type)
      result.append(entry)
  return result

